#region

using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

#endregion

namespace GGEditor.API.Utility.Forms
{
    [ToolboxItem(true)]
    public class InterceptedTabControl : TabControl
    {
        private int _tabHeight;
        private bool enableTabSelection = true;

        public InterceptedTabControl()
        {
            //SetStyle(ControlStyles.Selectable, false);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        }

        public bool EnableTabSelection
        {
            get { return enableTabSelection; }
            set { enableTabSelection = value; }
        }

        public int TabHeight
        {
            get
            {
                if (_tabHeight == 0) {
                    using (new VisualUpdate(this)) {
                        TabPage testPage = new TabPage();
                        TabPages.Add(testPage);
                        int y2 = testPage.RectangleToScreen(testPage.ClientRectangle).Top;
                        int y1 = RectangleToScreen(Bounds).Top;
                        _tabHeight = y2 - y1;
                        TabPages.Remove(testPage);
                    }
                }
                return _tabHeight;
            }
        }

        public event TabControlEventHandler TabChosen = delegate { };
        public event TabControlEventHandler TabChanging = delegate { };
        public event TabControlEventHandler TabChanged = delegate { };

        public void OnTabChosen(int tabIndex)
        {
            if (!EnableTabSelection)
                return;

            TabPage tabPage = TabPages[tabIndex];
            TabControlEventArgs e = new TabControlEventArgs(
                tabPage, tabIndex, TabControlAction.Selecting);
            TabChosen(this, e);
        }

        //protected override bool ShowFocusCues { get { return false; } }

        public new void SelectTab(int tabIndex)
        {
            if (tabIndex < 0 || tabIndex >= TabCount)
                return;

            //SetStyle(ControlStyles.Selectable, false);

            TabChanging(
                this,
                new TabControlEventArgs(TabPages[tabIndex], tabIndex, TabControlAction.Deselecting));

            base.SelectTab(tabIndex);

            TabChanged(
                this,
                new TabControlEventArgs(TabPages[tabIndex], tabIndex, TabControlAction.Selected));
        }

        public void InsertTab(int tabIndex, TabPage tabPage)
        {
            TabPages.Insert(tabIndex, tabPage);
        }

        public virtual void RemoveTab(int tabIndex)
        {
            TabPages.RemoveAt(tabIndex);
        }

        #region Event Overrides

        private static int WM_MOUSEDOWN = 0x201;

        protected override void WndProc(ref Message msg)
        {
            if (msg.Msg == WM_MOUSEDOWN) {
                int tabIndex = FindTab(new Point(msg.LParam.ToInt32()));
                if (tabIndex >= 0) //&& tabIndex != SelectedIndex)
                {
                    OnTabChosen(tabIndex);
                    return;
                }
            }
            base.WndProc(ref msg);
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (keyData == (Keys.Tab | Keys.Control) ||
                keyData == (Keys.Tab | Keys.Control | Keys.Shift)) {
                int tabIndex = GetNextTab((keyData & Keys.Shift) == Keys.None);
                if (tabIndex >= 0 && tabIndex != SelectedIndex)
                    OnTabChosen(tabIndex);
                return true;
            }
            return base.ProcessCmdKey(ref msg, keyData);
        }

        protected override void OnKeyDown(KeyEventArgs ke)
        {
            if (ke.KeyCode == Keys.Left || ke.KeyCode == Keys.Right) {
                //int tabIndex = GetNextTab(ke.KeyCode == Keys.Right);
                //if (tabIndex >= 0 && tabIndex != SelectedIndex)
                //{
                //    OnTabChosen(tabIndex);
                //}
                ke.Handled = true;
            }
            base.OnKeyDown(ke);
        }

        public void ChooseNextTab()
        {
            OnTabChosen(GetNextTab(true));
        }

        public void ChoosePreviousTab()
        {
            OnTabChosen(GetNextTab(false));
        }

        private int GetNextTab(bool forward)
        {
            if (forward)
                return (SelectedIndex + 1 >= TabCount) ? 0 : SelectedIndex + 1;
            return (SelectedIndex - 1 < 0) ? TabCount - 1 : SelectedIndex - 1;
        }

        private int FindTab(Point point)
        {
            for (int tabIndex = 0; tabIndex < TabCount; tabIndex++) {
                if (GetTabRect(tabIndex).Contains(point))
                    return tabIndex;
            }
            return -1;
        }

        #endregion
    }
}